/****************************************************************************
** Copyright (c) quickfixengine.org  All rights reserved.
**
** This file is part of the QuickFIX FIX Engine
**
** This file may be distributed under the terms of the quickfixengine.org
** license as defined by quickfixengine.org and appearing in the file
** LICENSE included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.quickfixengine.org/LICENSE for licensing information.
**
** Contact ask@quickfixengine.org if any conditions of this licensing are
** not clear to you.
**
****************************************************************************/

#ifdef _MSC_VER
#include "stdafx.h"
#else
#include "config.h"
#endif
#include "CallStack.h"

#include "DataDictionary.h"
#include "Message.h"
#include <fstream>
#include <memory>

#ifdef HAVE_LIBXML
#include "LIBXML_DOMDocument.h"
#elif _MSC_VER
#include "MSXML_DOMDocument.h"
#else
#include "LIBXML_DOMDocument.h"
#endif

#ifdef _MSC_VER
#define RESET_AUTO_PTR(OLD, NEW) OLD = NEW;
#else
#define RESET_AUTO_PTR(OLD, NEW) OLD.reset( NEW.release() );
#endif

namespace FIX
{
	DataDictionary::DataDictionary()
		: m_hasVersion( false ), m_checkFieldsOutOfOrder( true ),
		m_checkFieldsHaveValues( true ), m_checkUserDefinedFields( true ),
		m_orderedFieldsArray(0) {}

	DataDictionary::DataDictionary( std::istream& stream )
		throw( ConfigError )
		: m_hasVersion( false ), m_checkFieldsOutOfOrder( true ),
		m_checkFieldsHaveValues( true ), m_checkUserDefinedFields( true ),
		m_orderedFieldsArray(0)
	{
		readFromStream( stream );
	}

	DataDictionary::DataDictionary( const std::string& url )
		throw( ConfigError )
		: m_hasVersion( false ), m_checkFieldsOutOfOrder( true ),
		m_checkFieldsHaveValues( true ), m_checkUserDefinedFields( true ),
		m_orderedFieldsArray(0)
	{
		readFromURL( url );
	}

	DataDictionary::DataDictionary( const DataDictionary& copy )
	{
		*this = copy;
	}

	DataDictionary::~DataDictionary()
	{
		FieldToGroup::iterator i;
		for ( i = m_groups.begin(); i != m_groups.end(); ++i )
			delete i->second.second;
		if( m_orderedFieldsArray )
			delete [] m_orderedFieldsArray;
	}

	DataDictionary& DataDictionary::operator=( const DataDictionary& rhs )
	{ QF_STACK_PUSH(DataDictionary::operator=)

	m_hasVersion = rhs.m_hasVersion;
	m_checkFieldsOutOfOrder = rhs.m_checkFieldsOutOfOrder;
	m_checkFieldsHaveValues = rhs.m_checkFieldsHaveValues;
	m_checkUserDefinedFields = rhs.m_checkUserDefinedFields;
	m_beginString = rhs.m_beginString;
	m_messageFields = rhs.m_messageFields;
	m_requiredFields = rhs.m_requiredFields;
	m_messages = rhs.m_messages;
	m_fields = rhs.m_fields;
	m_orderedFields = rhs.m_orderedFields;
	m_orderedFieldsArray = 0;
	m_headerFields = rhs.m_headerFields;
	m_trailerFields = rhs.m_trailerFields;
	m_fieldTypes = rhs.m_fieldTypes;
	m_fieldValues = rhs.m_fieldValues;
	m_fieldNames = rhs.m_fieldNames;
	m_names = rhs.m_names;
	m_valueNames = rhs.m_valueNames;

	FieldToGroup::const_iterator i = rhs.m_groups.begin();
	for ( ; i != rhs.m_groups.end(); ++i )
	{
		addGroup( i->first.first, i->first.second,
			i->second.first, *i->second.second );
	}
	m_Message2TemplateId = rhs.m_Message2TemplateId;
	m_TemplateId2Message = rhs.m_TemplateId2Message;
	m_SortedFieldValues = rhs.m_SortedFieldValues;
	return *this;

	QF_STACK_POP
	}

	void DataDictionary::validate( const Message& message )
		throw( std::exception )
	{ QF_STACK_PUSH(DataDictionary::validate)

	const Header& header = message.getHeader();
	const BeginString& beginString = FIELD_GET_REF( header, BeginString );
	const MsgType& msgType = FIELD_GET_REF( header, MsgType );

	std::string ddBeginString = getVersion();
	if ( m_hasVersion && m_beginString != beginString )
		throw UnsupportedVersion();

	int field = 0;
	if ( m_checkFieldsOutOfOrder && !message.hasValidStructure(field) )
		throw TagOutOfOrder(field);

	if ( m_hasVersion )
	{
		checkMsgType( msgType );
		checkHasRequired( message.getHeader(), message, message.getTrailer(), msgType );
	}

	iterate( message.getHeader(), msgType );
	iterate( message.getTrailer(), msgType );
	iterate( message, msgType );

	QF_STACK_POP
	}

	void DataDictionary::iterate( const FieldMap& map, const MsgType& msgType )
	{ QF_STACK_PUSH(DataDictionary::iterate)

	int lastField = 0;

	FieldMap::iterator i;
	for ( i = map.begin(); i != map.end(); ++i )
	{
		const FieldBase& field = i->second;
		if( i != map.begin() && (field.getField() == lastField) )
			throw RepeatedTag( lastField );
		checkHasValue( field );

		if ( m_hasVersion )
		{
			checkValidFormat( field );
			checkValue( field );
		}

		if ( m_beginString.getValue().length() && shouldCheckTag(field) )
		{
			checkValidTagNumber( field );
			if ( !Message::isHeaderField( field, this )
				&& !Message::isTrailerField( field, this ) )
			{
				checkIsInMessage( field, msgType );
				checkGroupCount( field, map, msgType );
			}
		}
		lastField = field.getField();
	}

	QF_STACK_POP
	}

	void DataDictionary::readFromURL( const std::string& url )
		throw( ConfigError )
	{ QF_STACK_PUSH(DataDictionary::readFromURL)
	try
	{
		try
		{
#ifdef HAVE_LIBXML
			DOMDocumentPtr pDoc = DOMDocumentPtr(new LIBXML_DOMDocument());
#elif _MSC_VER
			DOMDocumentPtr pDoc = DOMDocumentPtr(new MSXML_DOMDocument());
#else
			DOMDocumentPtr pDoc = DOMDocumentPtr(new LIBXML_DOMDocument());
#endif

			if(!pDoc->load(url))
				throw ConfigError(url + ": Could not parse data from fix dictionary file");
			readFromDocument( pDoc );
		}
		catch ( ConfigError& e )
		{
			try
			{
#ifdef HAVE_LIBXML
				DOMDocumentPtr pDoc = DOMDocumentPtr(new LIBXML_DOMDocument());
#elif _MSC_VER
				DOMDocumentPtr pDoc = DOMDocumentPtr(new MSXML_DOMDocument());
#else
				DOMDocumentPtr pDoc = DOMDocumentPtr(new LIBXML_DOMDocument());
#endif

				if(!pDoc->load(url))
					throw ConfigError(url + ":" + e.what() + ": Could not parse data from fast dictionary file");
				pDoc->removeComments(); //try to FAST template format
				readFromFASTDocument( pDoc );
			}
			catch( ConfigError& e )
			{
				throw ConfigError( url + ": " + e.what() );
			}
			catch( Exception& e )
			{
				throw ConfigError( url + ": " + e.what() );
			}
		}
	}
	catch( ConfigError& e )
	{
		throw ConfigError( url + ": " + e.what() );
	}
	catch( Exception& e )
	{
		throw ConfigError( url + ": " + e.what() );
	}


	QF_STACK_POP
	}

	void DataDictionary::readFromStream( std::istream& stream )
		throw( ConfigError )
	{ QF_STACK_PUSH(DataDictionary::readFromStream)

	try
	{

#ifdef HAVE_LIBXML
		DOMDocumentPtr pDoc = DOMDocumentPtr(new LIBXML_DOMDocument());
#elif _MSC_VER
		DOMDocumentPtr pDoc = DOMDocumentPtr(new MSXML_DOMDocument());
#else
		DOMDocumentPtr pDoc = DOMDocumentPtr(new LIBXML_DOMDocument());
#endif
		if(!pDoc->load(stream))
			throw ConfigError("Could not parse data from fix dictionary stream");
		readFromDocument( pDoc );
	}
	catch ( ConfigError& e )
	{
#ifdef HAVE_LIBXML
		DOMDocumentPtr pDoc = DOMDocumentPtr(new LIBXML_DOMDocument());
#elif _MSC_VER
		DOMDocumentPtr pDoc = DOMDocumentPtr(new MSXML_DOMDocument());
#else
		DOMDocumentPtr pDoc = DOMDocumentPtr(new LIBXML_DOMDocument());
#endif
		if(!pDoc->load(stream))
			throw ConfigError(std::string(e.what()) + ":Could not parse data from fast dictionary stream");		  
		pDoc->removeComments(); //try to FAST template format
		readFromFASTDocument( pDoc );
	}

	QF_STACK_POP
	}

	void DataDictionary::readFromDocument( DOMDocumentPtr pDoc )
		throw( ConfigError )
	{ QF_STACK_PUSH(DataDictionary::readFromDocument)


	// VERSION
	DOMNodePtr pFixNode = pDoc->getNode("/fix");
	if(!pFixNode.get())
		throw ConfigError("Could not parse data dictionary file"
		", or no <fix> node found at root");
	DOMAttributesPtr attrs = pFixNode->getAttributes();
	std::string base;
	if(!attrs->get("base", base))
		throw ConfigError("base attribute not found on <fix>");

	std::string major;
	if(!attrs->get("major", major))
		throw ConfigError("major attribute not found on <fix>");
	std::string minor;
	if(!attrs->get("minor", minor))
		throw ConfigError("minor attribute not found on <fix>");
	setVersion(base + major + "." + minor);

	// FIELDS
	DOMNodePtr pFieldsNode = pDoc->getNode("/fix/fields");
	if(!pFieldsNode.get())
		throw ConfigError("<fields> section not found in data dictionary");

	DOMNodePtr pFieldNode = pFieldsNode->getFirstChildNode();
	if(!pFieldNode.get()) throw ConfigError("No fields defined");

	while(pFieldNode.get())
	{
		if(pFieldNode->getName() == "field")
		{
			DOMAttributesPtr attrs = pFieldNode->getAttributes();
			std::string name;
			if(!attrs->get("name", name))
				throw ConfigError("<field> does not have a name attribute");

			std::string number;
			if(!attrs->get("number", number))
				throw ConfigError("<field> " + name + " does not have a number attribute");
			int num = atol(number.c_str());
			std::string type;
			if(!attrs->get("type", type))
				throw ConfigError("<field> " + name + " does not have a type attribute");
			addField(num);
			addFieldType(num, XMLTypeToType(type));
			addFieldName(num, name);

			DOMNodePtr pFieldValueNode = pFieldNode->getFirstChildNode();
			while(pFieldValueNode.get())
			{
				if(pFieldValueNode->getName() == "value")
				{
					DOMAttributesPtr attrs = pFieldValueNode->getAttributes();
					std::string enumeration;
					if(!attrs->get("enum", enumeration))
						throw ConfigError("<value> does not have enum attribute in field " + name);
					addFieldValue(num, enumeration);
					std::string description;
					if(attrs->get("description", description))
						addValueName(num, enumeration, description);
				}
				RESET_AUTO_PTR(pFieldValueNode, pFieldValueNode->getNextSiblingNode());
			}
		}
		RESET_AUTO_PTR(pFieldNode, pFieldNode->getNextSiblingNode());
	}

	int headerSlot = 0;
	// HEADER
	DOMNodePtr pHeaderNode = pDoc->getNode("/fix/header");
	if(!pHeaderNode.get())
		throw ConfigError("<header> section not found in data dictionary");

	DOMNodePtr pHeaderFieldNode = pHeaderNode->getFirstChildNode();
	if(!pHeaderFieldNode.get()) throw ConfigError("No header fields defined");

	std::stringstream htid;
	htid << eFAST_HDR_TEMPLATE;
	addMsgType(htid.str());
	addTemplateID(htid.str(), eFAST_HDR_TEMPLATE);

	while(pHeaderFieldNode.get())
	{
		if(pHeaderFieldNode->getName() == "field" || pHeaderFieldNode->getName() == "group" )
		{
			DOMAttributesPtr attrs = pHeaderFieldNode->getAttributes();
			std::string name;
			if(!attrs->get("name", name))
				throw ConfigError("<field> does not have a name attribute");

			std::string required = "Y";
			bool isRequired = true;
			if (attrs->get("required", required))
				(required == "N" || required == "n" )? isRequired  = false : isRequired  = true;

			addHeaderField(lookupXMLFieldNumber(pDoc.get(), name), isRequired);

			std::string value="";
			if ( !attrs->get("value", value) )
				value = "none";

			std::string ref = "";
			if ( !attrs->get("ref", ref) )
				ref = "none";

			std::string _operator = "";
			if ( !attrs->get("operator", _operator) )
				_operator = "none";

			int num = lookupXMLFieldNumber(pDoc.get(), name);

			eFAST_TYPE FastType;
			getFieldType(num, FastType);
			eFAST_OP FastOperator;
			getFieldOpearator(_operator, FastOperator);
			FastTag ft(FastType, isRequired, FastOperator, eFAST_HDR_TEMPLATE, headerSlot , num, value, ref, name);
			addMsgFieldTag(ft);
			headerSlot++;

		}
		if(pHeaderFieldNode->getName() == "group")
		{
			DOMAttributesPtr attrs = pHeaderFieldNode->getAttributes();
			std::string required = "Y";
			bool isRequired = true;
			if (attrs->get("required", required))
				(required == "N" || required == "n" )? isRequired  = false : isRequired  = true;

			addXMLGroup(pDoc.get(), pHeaderFieldNode.get(), "_header_", *this, isRequired);
		}

		RESET_AUTO_PTR(pHeaderFieldNode, pHeaderFieldNode->getNextSiblingNode());
	}

	// TRAILER
	int trailerSlot = 0;
	DOMNodePtr pTrailerNode = pDoc->getNode("/fix/trailer");
	if(!pTrailerNode.get())
		throw ConfigError("<trailer> section not found in data dictionary");

	DOMNodePtr pTrailerFieldNode = pTrailerNode->getFirstChildNode();
	if(!pTrailerFieldNode.get()) throw ConfigError("No trailer fields defined");

	std::stringstream ttid;
	ttid << eFAST_TRL_TEMPLATE;
	addMsgType(ttid.str());
	addTemplateID(ttid.str(), eFAST_TRL_TEMPLATE);

	while(pTrailerFieldNode.get())
	{
		if(pTrailerFieldNode->getName() == "field" || pTrailerFieldNode->getName() == "group" )
		{
			DOMAttributesPtr attrs = pTrailerFieldNode->getAttributes();
			std::string name;
			if(!attrs->get("name", name))
				throw ConfigError("<field> does not have a name attribute");
			std::string required = "Y";
			bool isRequired = true;
			if (attrs->get("required", required))
				(required == "N" || required == "n" )? isRequired  = false : isRequired  = true;

			addTrailerField(lookupXMLFieldNumber(pDoc.get(), name), isRequired);

			std::string value="";
			if ( !attrs->get("value", value) )
				value = "none";

			std::string ref = "";
			if ( !attrs->get("ref", ref) )
				ref = "none";

			std::string _operator = "";
			if ( !attrs->get("operator", _operator) )
				_operator = "none";


			int num = lookupXMLFieldNumber(pDoc.get(), name);

			eFAST_TYPE FastType;
			getFieldType(num, FastType);
			eFAST_OP FastOperator;
			getFieldOpearator(_operator, FastOperator);
			FastTag ft(FastType, isRequired, FastOperator, eFAST_TRL_TEMPLATE, trailerSlot , num, value, ref, name);
			addMsgFieldTag(ft);
			trailerSlot++;

		}
		if(pTrailerFieldNode->getName() == "group")
		{
			DOMAttributesPtr attrs = pTrailerFieldNode->getAttributes();
			std::string required = "Y";
			bool isRequired = true;
			if (attrs->get("required", required))
				(required == "N" || required == "n" )? isRequired  = false : isRequired  = true;

			addXMLGroup(pDoc.get(), pTrailerFieldNode.get(), "_trailer_", *this, isRequired);
		}

		RESET_AUTO_PTR(pTrailerFieldNode, pTrailerFieldNode->getNextSiblingNode());
	}

	// MSGTYPE
	DOMNodePtr pMessagesNode = pDoc->getNode("/fix/messages");
	if(!pMessagesNode.get())
		throw ConfigError("<messages> section not found in data dictionary");

	DOMNodePtr pMessageNode = pMessagesNode->getFirstChildNode();
	if(!pMessageNode.get()) throw ConfigError("No messages defined");

	while(pMessageNode.get())
	{
		if(pMessageNode->getName() == "message")
		{
			int fieldSlot = 0;

			DOMAttributesPtr attrs = pMessageNode->getAttributes();
			std::string msgtype;
			std::string tid;
			if(!attrs->get("msgtype", msgtype))
				throw ConfigError("<field> does not have a name attribute");
			addMsgType(msgtype);

			if(attrs->get("tid", tid))
				addTemplateID(msgtype, atoi(tid.c_str()));

			std::string name;
			if(attrs->get("name", name))
				addValueName( 35, msgtype, name );

			DOMNodePtr pMessageFieldNode = pMessageNode->getFirstChildNode();
			if( !pMessageFieldNode.get() )
			{
				throw ConfigError("<message> contains no fields");
			}
			while( pMessageFieldNode.get() )
			{
				if(pMessageFieldNode->getName() == "field"
					|| pMessageFieldNode->getName() == "group")
				{
					DOMAttributesPtr attrs = pMessageFieldNode->getAttributes();
					std::string name;
					if(!attrs->get("name", name))
						throw ConfigError("<field> does not have a name attribute");

					int num = lookupXMLFieldNumber(pDoc.get(), name);
					addMsgField(msgtype, num);

					std::string value="";
					if ( !attrs->get("value", value) )
						value = "none";

					std::string _operator = "";
					if ( !attrs->get("operator", _operator) )
						_operator = "none";

					std::string ref = "";
					if ( !attrs->get("ref", ref) )
						ref = "none";

					std::string required = "Y";
					bool isRequired = true;
					if (attrs->get("required", required))
						(required == "N" || required == "n" )? isRequired  = false : isRequired  = true;

					if( isRequired )
					{
						addRequiredField(msgtype, num);
					}
					eFAST_TYPE FastType;
					getFieldType(num, FastType);
					eFAST_OP FastOperator;
					getFieldOpearator(_operator, FastOperator);
					FastTag ft(FastType, isRequired, FastOperator, atoi(tid.c_str()), fieldSlot , num, value, ref, name);
					addMsgFieldTag(ft);
					fieldSlot++;
				}
				else if(pMessageFieldNode->getName() == "component")
				{
					DOMAttributesPtr attrs = pMessageFieldNode->getAttributes();
					std::string required = "Y";
					bool isRequired = false;
					if (attrs->get("required", required))
						(required == "N" || required == "n" )? isRequired  = false : isRequired  = true;
					addXMLComponentFields(pDoc.get(), pMessageFieldNode.get(),
						msgtype, *this, isRequired);
				}
				if(pMessageFieldNode->getName() == "group")
				{

					DOMAttributesPtr attrs = pMessageFieldNode->getAttributes();
					std::string required = "Y";
					bool isRequired = true;
					if (attrs->get("required", required))
						(required == "N" || required == "n" )? isRequired  = false : isRequired  = true;

					std::string gtid;
					if(attrs->get("tid", gtid) && m_TemplateId2Message.find(atoi(gtid.c_str())) == m_TemplateId2Message.end())
					{
						addTemplateID(gtid, atoi(gtid.c_str()));
						addXMLGroup(pDoc.get(), pMessageFieldNode.get(), msgtype, *this, isRequired, atoi(gtid.c_str()) );
					}
					else
						addXMLGroup(pDoc.get(), pMessageFieldNode.get(), msgtype, *this, isRequired );
				}
				RESET_AUTO_PTR(pMessageFieldNode,
					pMessageFieldNode->getNextSiblingNode());
			}
		}
		RESET_AUTO_PTR(pMessageNode, pMessageNode->getNextSiblingNode());
	}

	QF_STACK_POP
	}


	/////////////////////////////////////////////////////
	void DataDictionary::readFromFASTDocument( DOMDocumentPtr pDoc )
		throw( ConfigError )
	{ QF_STACK_PUSH(DataDictionary::readFromFASTDocument)


	// VERSION
	DOMNodePtr pFixNode = pDoc->getNode("/templates");
	if(!pFixNode.get())
		throw ConfigError("Could not parse data dictionary file"
		", or no <templates> node found at root");
	DOMAttributesPtr attrs = pFixNode->getAttributes();
	std::string xmlns;
	// if(!attrs->get("xmlns", xmlns))
	//  throw ConfigError("xmlns attribute not found on <xmlns>");

	setVersion("1.1");


	DOMNodePtr pMessageNode = pFixNode->getFirstChildNode();
	if(!pMessageNode.get()) throw ConfigError("No messages defined");

	while(pMessageNode.get())
	{
		std::vector<int> requiredFlds;
		std::vector<int> msgFlds;
		if(pMessageNode->getName() == "template")
		{
			requiredFlds.clear();
			msgFlds.clear();
			int fieldSlot = 0;
			bool bMsgTypeFound = false;

			DOMAttributesPtr attrs = pMessageNode->getAttributes();
			std::string tid;

			if(!attrs->get("id", tid))
				throw ConfigError("No templateID defined");

			std::string name;
			if(!attrs->get("name", name))
				throw ConfigError("No message name defined");

			DOMNodePtr pMessageFieldNode = pMessageNode->getFirstChildNode();
			if( !pMessageFieldNode.get() )
			{
				throw ConfigError("<message> contains no fields");
			}

			std::string msgType;
			bool bPMapReq = true;

			while( pMessageFieldNode.get() )
			{

				bool bRequired = true;

				if(pMessageFieldNode->getName() != "group"
					&& pMessageFieldNode->getName() != "sequence")
				{
					int iField =0;
					AddXMLFASTField(pDoc.get(), pMessageFieldNode.get(), bMsgTypeFound,
						atoi(tid.c_str()), msgType, bRequired, fieldSlot, *this, iField, name, bPMapReq);

					if ( bMsgTypeFound )
					{
						for ( size_t i = 0; i < requiredFlds.size(); i++ )
						{
							addRequiredField(msgType, requiredFlds[i]);
						}
						requiredFlds.clear();
						for ( size_t t = 0; t < msgFlds.size(); t++ )
						{
							addMsgField(msgType, msgFlds[t]);
						}
						msgFlds.clear();
						addMsgField(msgType, iField);
					}
					else
					{
						msgFlds.push_back(iField);
					}

					if( bRequired )
					{
						if(bMsgTypeFound)
							addRequiredField(msgType, iField);
						else
							requiredFlds.push_back(iField);
					}
				}
				else if(pMessageFieldNode->getName() == "sequence"
					|| pMessageFieldNode->getName() == "group")
				{

					addXMLFASTGroup( pDoc.get(), pMessageFieldNode.get(),
						msgType, atoi(tid.c_str()), fieldSlot, 
						*this, bPMapReq);
				}

				RESET_AUTO_PTR(pMessageFieldNode,
					pMessageFieldNode->getNextSiblingNode());
			}
		}
		RESET_AUTO_PTR(pMessageNode, pMessageNode->getNextSiblingNode());
	}

	QF_STACK_POP
	}
	/////////////////////////////////////////////////////



	int DataDictionary::AddXMLFASTField(DOMDocument* pDoc, DOMNode* pMessageFieldNode, bool &bMsgTypeFound,
		int tid, std::string &msgType, bool &bRequired,
		int &fieldSlot, DataDictionary &DD, int &ifield,
		const std::string & msgName, bool &bpMapReq) throw( ConfigError )
	{
		QF_STACK_PUSH(DataDictionary::AddXMLFASTField)

			int unknownMsg = 0;
		DOMAttributesPtr attrs = pMessageFieldNode->getAttributes();
		std::string dataType = pMessageFieldNode->getName();

		if (dataType == "length") 
		{
			// For GroupLength we take bRequired from the caller
			dataType = "numInGrp";
		}
		else
		{
			std::string required = "mandatory";
			attrs->get("presence", required);
			(required == "optional" )? bRequired  = false : bRequired  = true;
		}
		std::string fldname;
		if(!attrs->get("name", fldname))
			throw ConfigError(pMessageFieldNode->getName() + "-does not have a name attribute");

		std::string number;
		if(!attrs->get("id", number))
			throw ConfigError(pMessageFieldNode->getName()+ " - " + fldname + " does not have a number attribute");
		int num = atol(number.c_str());

		DD.addFASTField(num);
		DD.addFASTFieldType(num, XMLFASTTypeToType(dataType));
		DD.addFASTFieldName(num, fldname);

		addFASTField(num);
		addFASTFieldType(num, XMLFASTTypeToType(dataType));
		addFASTFieldName(num, fldname);
		ifield = num;

		//int num = lookupXMLFieldNumber(pDoc.get(), name);

		std::string value="none";
		std::string _operator = "none";
		std::string ref = "none";
		int iRefId = 0;

		if (pMessageFieldNode->getName() == "templateRef" )
		{
			if ( !attrs->get("id", ref) )
				ref = "none";
		}
		else
		{
			//tid = 86
			//num = 286
			if ( dataType == "numInGrp" )
			{
				iRefId = tid + num;
				iRefId |= 0x2000;
				char szTemp[255];
				sprintf(szTemp,"%d", iRefId);
				ref = szTemp;
			}
		}




		DOMNodePtr pMessageFieldOpNode = pMessageFieldNode->getFirstChildNode();
		std::string exOp;
		std::string exValue = "none"; 
		std::string manOp;
		std::string manValue = "none"; 
		eFAST_OP FastOperator = eFAST_OP_NONE;

		if( pMessageFieldOpNode.get() )
		{
			if ( pMessageFieldOpNode->getName() == "exponent" )
			{
				exOp = "none";
				exValue = "none";
				DOMNodePtr expNode = pMessageFieldOpNode->getFirstChildNode();
				if ( expNode.get() )
				{
					exOp= expNode->getName();
					DOMAttributesPtr attrsExOp = expNode->getAttributes();
					attrsExOp->get("value", exValue);
				}
				u32 op;
				getFieldOpearator(exOp, (eFAST_OP &)op);
				FastOperator = (eFAST_OP)(op << 3 );

				manOp = "none";
				manValue = "none";

				pMessageFieldOpNode = pMessageFieldOpNode->getNextSiblingNode();
				if ( pMessageFieldOpNode->getName() == "mantissa" )
				{
					DOMNodePtr manNode = pMessageFieldOpNode->getFirstChildNode();
					if (manNode.get())
					{
						manOp= manNode->getName();
						DOMAttributesPtr attrsmanOp = manNode->getAttributes();
						attrsmanOp->get("value", manValue);
					}
					getFieldOpearator(manOp, (eFAST_OP &)op);
					FastOperator = (eFAST_OP)((u32)FastOperator | op);
				}

				std::ostringstream strValue ;
				strValue << exValue << ((manValue == "none")? ".none" : ("." + manValue));
				value = strValue.str();
			}
			else
			{
				_operator = pMessageFieldOpNode->getName();
				getFieldOpearator(_operator, FastOperator);
				DOMAttributesPtr attrsOp = pMessageFieldOpNode->getAttributes();
				attrsOp->get("value", value);
			}
		}

		if ( num == 35 )
		{

			if ( value != "none" )
				msgType = value;
			else
			{
				char szTemp[100];
				sprintf(szTemp, "XYZ%d", unknownMsg++);
				msgType = szTemp;
			}
			addMsgType(msgType);
			addTemplateID(msgType, tid);
			addValueName( 35, msgType, msgName );
			bMsgTypeFound = true;

		}

		eFAST_TYPE FastType;
		getFieldType(num, FastType);
		FastTag ft(FastType, bRequired, FastOperator, tid, fieldSlot , num, value, ref, fldname);
		bpMapReq = addMsgFieldTag(ft);
		fieldSlot++;

		return fieldSlot;

		QF_STACK_POP
	}

	int* DataDictionary::getOrderedFields() const
	{ QF_STACK_PUSH(DataDictionary::getOrderedFields)

	if( m_orderedFieldsArray ) return m_orderedFieldsArray;
	m_orderedFieldsArray = new int[m_orderedFields.size() + 1];

	int* i = m_orderedFieldsArray;
	OrderedFields::const_iterator iter;
	for( iter = m_orderedFields.begin(); iter != m_orderedFields.end(); *(i++) = *(iter++) ) {}
	*i = 0;
	return m_orderedFieldsArray;

	QF_STACK_POP
	}

	int DataDictionary::lookupXMLFieldNumber( DOMDocument* pDoc, DOMNode* pNode ) const
	{ QF_STACK_PUSH(DataDictionary::lookupXMLFieldNumber)

	DOMAttributesPtr attrs = pNode->getAttributes();
	std::string name;
	if(!attrs->get("name", name))
		throw ConfigError("No name given to field");
	return lookupXMLFieldNumber( pDoc, name );

	QF_STACK_POP
	}

	int DataDictionary::lookupXMLFieldNumber
		( DOMDocument* pDoc, const std::string& name ) const
	{ QF_STACK_PUSH(DataDictionary::lookupXMLFieldNumber)

	NameToField::const_iterator i = m_names.find(name);
	if( i == m_names.end() )
		throw ConfigError("Field " + name + " not defined in fields section");
	return i->second;

	QF_STACK_POP
	}

	int DataDictionary::addXMLComponentFields( DOMDocument* pDoc, DOMNode* pNode,
		const std::string& msgtype,
		DataDictionary& DD,
		bool componentRequired )
	{ QF_STACK_PUSH(DataDictionary::addXMLComponentFields)

	int firstField = 0;

	DOMAttributesPtr attrs = pNode->getAttributes();
	std::string name;
	if(!attrs->get("name", name))
		throw ConfigError("No name given to component");

	DOMNodePtr pComponentNode =
		pDoc->getNode("/fix/components/component[@name='" + name + "']");
	if(pComponentNode.get() == 0)
		throw ConfigError("Component not found");

	DOMNodePtr pComponentFieldNode = pComponentNode->getFirstChildNode();
	while(pComponentFieldNode.get())
	{
		if(pComponentFieldNode->getName() == "field"
			|| pComponentFieldNode->getName() == "group")
		{
			DOMAttributesPtr attrs = pComponentFieldNode->getAttributes();
			std::string name;
			if(!attrs->get("name", name))
				throw ConfigError("No name given to field");
			int field = lookupXMLFieldNumber(pDoc, name);
			if( firstField == 0 ) firstField = field;


			std::string required = "Y";
			bool isRequired = true;
			if (attrs->get("required", required))
				(required == "N" || required == "n" )? isRequired  = false : isRequired  = true;

			if(isRequired && componentRequired)
			{
				addRequiredField(msgtype, field);
			}

			DD.addField(field);
			DD.addMsgField(msgtype, field);
		}
		if(pComponentFieldNode->getName() == "group")
		{
			DOMAttributesPtr attrs = pComponentFieldNode->getAttributes();
			std::string required = "Y";
			bool isRequired = true;
			if (attrs->get("required", required))
				(required == "N" || required == "n" )? isRequired  = false : isRequired  = true;

			addXMLGroup(pDoc, pComponentFieldNode.get(), msgtype, DD, isRequired);
		}
		RESET_AUTO_PTR(pComponentFieldNode,
			pComponentFieldNode->getNextSiblingNode());
	}
	return firstField;

	QF_STACK_POP
	}


	void DataDictionary::addXMLFASTGroup( DOMDocument* pDoc, DOMNode* pNode,
		const std::string& msgtype, int tid, int &groupFieldSlot,
		DataDictionary& DD, bool &bPmapReq) throw( ConfigError )
	{ QF_STACK_PUSH(DataDictionary::addXMLFASTGroup)

	DOMAttributesPtr attrs = pNode->getAttributes();
	int fieldSlot = 0;
	std::string name;
	if(!attrs->get("name", name))
		throw ConfigError("No name given to group");

	std::string presence = "mandatory";
	attrs->get("presence", presence);

	bool groupRequired = true;
	if ( presence == "optional" ) groupRequired = false;

	int group = 0;      // = lookupXMLFieldNumber( pDoc, name );
	int delim = 0;
	int field = 0;
	DataDictionary groupDD;
	DOMNodePtr node = pNode->getFirstChildNode();
	std::string groupName;
	std::string groupNum = "";
	bool bMsgTypeFound = true;

	int iMainTid = tid;

	if( node->getName() == "length" )
	{

		DOMAttributesPtr lenAttrs = node->getAttributes();
		if ( !lenAttrs->get("name", groupName) )
			throw ConfigError("No name given to group length field");
		if (!lenAttrs->get("id", groupNum) )
			throw ConfigError("No tag num given to group length");

		int grpNum = atol(groupNum.c_str());
		//addFASTField(grpNum);
		//addFASTFieldType(grpNum, XMLFASTTypeToType("numInGrp"));
		//addFASTFieldName(grpNum, groupName);
		groupDD.addFASTField( grpNum );
		//DD.addFASTField( grpNum );
		if(groupRequired)
		{
			groupDD.addRequiredField(msgtype, grpNum);
			//DD.addRequiredField(msgtype, grpNum);
		}
		group = grpNum;

		int iFld = 0;
		std::string msgTemp = msgtype;
		AddXMLFASTField(pDoc, node.get(), bMsgTypeFound,
			tid, msgTemp, groupRequired,
			groupFieldSlot, DD, iFld,
			groupName, bPmapReq);
		groupFieldSlot++;

		RESET_AUTO_PTR(node, node->getNextSiblingNode());

	}
	//tid = atol(groupNum.c_str());

	tid += group;
	tid |= 0x2000;

	addTemplateID(groupNum, tid);

	bool bGrpPmapReq = true;
	int iPmapReq = 0;
	std::string msgType = "XYG";
	while(node.get())
	{
		int iField = 0;
		if( node->getName() != "sequence" && node->getName() != "group" )
		{
			AddXMLFASTField(pDoc, node.get(), bMsgTypeFound,
				tid, msgType, groupRequired, fieldSlot, groupDD, iField, groupName, bGrpPmapReq);
		}
		else if( node->getName() == "sequence" || node->getName() == "group" )
		{

			addXMLFASTGroup( pDoc, node.get(), msgtype, tid, fieldSlot, groupDD, bGrpPmapReq);
		}

		if ( bGrpPmapReq )
			iPmapReq++;

		if( delim == 0 ) delim = iField;
		RESET_AUTO_PTR(node, node->getNextSiblingNode());
	}

	if ( iPmapReq == 0 )
	{
		//iMainTid
		//grpNum
		for ( FastTagVector::iterator start = DD.m_SortedFieldValues[iMainTid].begin(); start != DD.m_SortedFieldValues[iMainTid].end(); start++ )
		{
			if ( start->get_num() ==  group )
			{
				start->set_pmap_req(false);
			}
		}


	}
	if( delim ) DD.addGroup( msgtype, group, delim, groupDD );

	QF_STACK_POP
	}




	void DataDictionary::addXMLGroup( DOMDocument* pDoc, DOMNode* pNode,
		const std::string& msgtype,
		DataDictionary& DD, bool groupRequired, int tid )
	{ QF_STACK_PUSH(DataDictionary::addXMLGroup)

	DOMAttributesPtr attrs = pNode->getAttributes();
	int fieldSlot = 0;
	std::string name;
	if(!attrs->get("name", name))
		throw ConfigError("No name given to group");
	int group = lookupXMLFieldNumber( pDoc, name );
	int delim = 0;
	int field = 0;
	DataDictionary groupDD;
	DOMNodePtr node = pNode->getFirstChildNode();
	while(node.get())
	{
		if( node->getName() == "field" )
		{
			field = lookupXMLFieldNumber( pDoc, node.get() );
			groupDD.addField( field );

			DOMAttributesPtr attrs = node->getAttributes();
			std::string required = "Y";
			bool isRequired = true;
			if (attrs->get("required", required))
				(required == "N" || required == "n" )? isRequired  = false : isRequired  = true;

			std::string fieldname = "none";
			if(!attrs->get("name", fieldname))
				throw ConfigError("No name given to group's fieldname");

			if( isRequired )
			{
				groupDD.addRequiredField(msgtype, field);
			}
			if(tid)
			{
				std::string value="";
				if ( !attrs->get("value", value) )
					value = "none";

				std::string _operator = "";
				if ( !attrs->get("operator", _operator) )
					_operator = "none";

				std::string ref = "";
				if ( !attrs->get("ref", ref) )
					ref = "none";

				eFAST_TYPE FastType;
				getFieldType(field, FastType);
				eFAST_OP FastOperator;
				getFieldOpearator(_operator, FastOperator);
				FastTag ft(FastType, isRequired, FastOperator, tid, fieldSlot , field, value, ref, fieldname);
				addMsgFieldTag(ft);
				fieldSlot++;
			}
		}
		else if( node->getName() == "component" )
		{
			field = addXMLComponentFields( pDoc, node.get(), msgtype, groupDD, false );
		}
		else if( node->getName() == "group" )
		{
			field = lookupXMLFieldNumber( pDoc, node.get() );
			groupDD.addField( field );
			DOMAttributesPtr attrs = node->getAttributes();

			std::string required = "Y";
			bool isRequired = true;
			if (attrs->get("required", required))
				(required == "N" || required == "n" )? isRequired  = false : isRequired  = true;

			if(isRequired && groupRequired)
			{
				groupDD.addRequiredField(msgtype, field);
			}
			std::string gtid;
			if(attrs->get("tid", gtid))
			{
				if(tid)
				{
					std::string value="";
					if ( !attrs->get("value", value) )
						value = "none";

					std::string _operator = "";
					if ( !attrs->get("operator", _operator) )
						_operator = "none";

					std::string ref = "";
					if ( !attrs->get("ref", ref) )
						ref = "none";

					std::string fieldname = "none";
					if(!attrs->get("name", fieldname))
						throw ConfigError("No name given to group's fieldname");

					eFAST_TYPE FastType;
					getFieldType(field, FastType);
					eFAST_OP FastOperator;
					getFieldOpearator(_operator, FastOperator);
					FastTag ft(FastType, isRequired, FastOperator, tid, fieldSlot , field, value, ref, fieldname);
					addMsgFieldTag(ft);
					fieldSlot++;
				}

				addTemplateID(gtid, atoi(gtid.c_str()));
				addXMLGroup(pDoc, node.get(), msgtype, groupDD, isRequired, atoi(gtid.c_str()));
			}
			else
				addXMLGroup(pDoc, node.get(), msgtype, groupDD, isRequired);
		}
		if( delim == 0 ) delim = field;
		RESET_AUTO_PTR(node, node->getNextSiblingNode());
	}

	if( delim ) DD.addGroup( msgtype, group, delim, groupDD );

	QF_STACK_POP
	}

	TYPE::Type DataDictionary::XMLTypeToType( const std::string& type ) const
	{ QF_STACK_PUSH(DataDictionary::XMLTypeToType)

	if ( m_beginString < "FIX.4.2" && type == "CHAR" )
		return TYPE::String;

	if ( type == "STRING" ) return TYPE::String;
	if ( type == "CHAR" ) return TYPE::Char;
	if ( type == "PRICE" ) return TYPE::Price;
	if ( type == "INT" ) return TYPE::Int;
	if ( type == "UINT" ) return TYPE::UInt;
	if ( type == "LONG" ) return TYPE::Long;
	if ( type == "ULONG" ) return TYPE::ULong;
	if ( type == "AMT" ) return TYPE::Amt;
	if ( type == "QTY" ) return TYPE::Qty;
	if ( type == "CURRENCY" ) return TYPE::Currency;
	if ( type == "MULTIPLEVALUESTRING" ) return TYPE::MultipleValueString;
	if ( type == "EXCHANGE" ) return TYPE::Exchange;
	if ( type == "UTCTIMESTAMP" ) return TYPE::UtcTimeStamp;
	if ( type == "BOOLEAN" ) return TYPE::Boolean;
	if ( type == "LOCALMKTDATE" ) return TYPE::LocalMktDate;
	if ( type == "DATA" ) return TYPE::Data;
	if ( type == "FLOAT" ) return TYPE::Float;
	if ( type == "PRICEOFFSET" ) return TYPE::PriceOffset;
	if ( type == "MONTHYEAR" ) return TYPE::MonthYear;
	if ( type == "DAYOFMONTH" ) return TYPE::DayOfMonth;
	if ( type == "UTCDATE" ) return TYPE::UtcDate;
	if ( type == "UTCDATEONLY" ) return TYPE::UtcDateOnly;
	if ( type == "UTCTIMEONLY" ) return TYPE::UtcTimeOnly;
	if ( type == "NUMINGROUP" ) return TYPE::NumInGroup;
	if ( type == "PERCENTAGE" ) return TYPE::Percentage;
	if ( type == "SEQNUM" ) return TYPE::SeqNum;
	if ( type == "LONGSEQNUM" ) return TYPE::LongSeqNum;
	if ( type == "LENGTH" ) return TYPE::Length;
	if ( type == "COUNTRY" ) return TYPE::Country;
	if ( type == "TIME" ) return TYPE::UtcTimeStamp;
	return TYPE::Unknown;

	QF_STACK_POP
	}


	TYPE::Type DataDictionary::XMLFASTTypeToType( const std::string& type ) const
	{ QF_STACK_PUSH(DataDictionary::XMLFASTTypeToType)

	if ( type == "string" ) return TYPE::String;
	if ( type == "int32" ) return TYPE::Int;
	if ( type == "uInt32" ) return TYPE::UInt;
	if ( type == "int64" ) return TYPE::Long;
	if ( type == "uInt64" ) return TYPE::ULong;
	if ( type == "decimal" ) return TYPE::Float;
	if ( type == "numInGrp" ) return TYPE::NumInGroup;
	return TYPE::Unknown;

	QF_STACK_POP
	}
	eFAST_TYPE DataDictionary::TypeToFastType( const TYPE::Type& type ) const
	{ QF_STACK_PUSH(DataDictionary::TypeToFastType)

	if ( m_beginString < "FIX.4.2" && type == "CHAR" )
		return eFAST_TYPE_ASCII;


	if ( type == TYPE::String ) return eFAST_TYPE_ASCII;
	if ( type == TYPE::Char ) return eFAST_TYPE_I32;
	if ( type == TYPE::Price ) return eFAST_TYPE_DECMIAL;
	if ( type == TYPE::Int ) return eFAST_TYPE_I32;
	if ( type == TYPE::UInt ) return eFAST_TYPE_U32;
	if ( type == TYPE::Long ) return eFAST_TYPE_I64;
	if ( type == TYPE::ULong ) return eFAST_TYPE_U64;
	if ( type == TYPE::Amt ) return eFAST_TYPE_I32;
	if ( type == TYPE::Qty ) return eFAST_TYPE_DECMIAL;
	if ( type == TYPE::Currency ) return eFAST_TYPE_I32;
	if ( type == TYPE::MultipleValueString ) return eFAST_TYPE_UNICODE;
	if ( type == TYPE::Exchange ) return eFAST_TYPE_ASCII;
	if ( type == TYPE::UtcTimeStamp ) return eFAST_TYPE_ASCII;
	if ( type ==  TYPE::Boolean ) return eFAST_TYPE_ASCII;
	if ( type == TYPE::LocalMktDate ) return eFAST_TYPE_ASCII;
	if ( type == TYPE::Data ) return eFAST_TYPE_ASCII;
	if ( type == TYPE::Float ) return eFAST_TYPE_DECMIAL;
	if ( type == TYPE::PriceOffset ) return eFAST_TYPE_I32;
	if ( type == TYPE::MonthYear ) return eFAST_TYPE_ASCII;
	if ( type == TYPE::DayOfMonth ) return eFAST_TYPE_ASCII;
	if ( type == TYPE::UtcDate ) return eFAST_TYPE_ASCII;
	if ( type == TYPE::UtcDateOnly ) return eFAST_TYPE_ASCII;
	if ( type == TYPE::UtcTimeOnly ) return eFAST_TYPE_ASCII;
	if ( type == TYPE::NumInGroup ) return eFAST_TYPE_GROUP;
	if ( type == TYPE::Percentage ) return eFAST_TYPE_DECMIAL;
	if ( type == TYPE::SeqNum ) return eFAST_TYPE_U32;
	if ( type == TYPE::LongSeqNum ) return eFAST_TYPE_U64;
	if ( type == TYPE::Length ) return eFAST_TYPE_I32;
	if ( type == TYPE::Country ) return eFAST_TYPE_ASCII;
	if ( type == TYPE::UtcTimeStamp ) return eFAST_TYPE_ASCII;
	throw "Incorrect id";
	QF_STACK_POP
	}

  bool DataDictionary::resetDictionary(FASTApi& iFast, FASTApi& oFast, unsigned int tid ) const
  {
	  i32 exponent = 0;
	  i64 mantissa = 0;
	  std::string::size_type dpos;
	  u8 alreadySet = 0;


  	  TID2OrderedFields::const_iterator itr = m_SortedFieldValues.begin();
	  TID2OrderedFields::const_iterator itrend = m_SortedFieldValues.end();
	  for (; itr != itrend; ++itr)
	  {
		  if ( itr->first != tid && tid != 0 ) continue;
		  FastTagVector::const_iterator ii = itr->second.begin();
		  FastTagVector::const_iterator iiend = itr->second.end();
		  for( ; ii != iiend; ++ii)
		  {
			  alreadySet = 0;
			  switch( ii->m_type )
			  {
			  case eFAST_TYPE_ASCII:
			  case eFAST_TYPE_UNICODE:
				  {
					  FastField ff(ii->m_init.c_str());
					  iFast.set (ii->m_tag, ff);
					  oFast.set (ii->m_tag, ff);
				  }
				  break;
			  case eFAST_TYPE_I32:
				  {
					  FastField ff((i32)atoi(ii->m_init.c_str()));
					  iFast.set( ii->m_tag, ff );
					  oFast.set( ii->m_tag, ff );
				  }
				  break;
			  case eFAST_TYPE_U32:
			  case eFAST_TYPE_GROUP:
				  {
					  FastField ff((u32)atoi(ii->m_init.c_str()));
					  iFast.set( ii->m_tag, ff);
					  oFast.set( ii->m_tag, ff);
					  if ( ii->m_type == eFAST_TYPE_GROUP )
					  {
						  resetDictionary(iFast, oFast,  atoi(ii->m_ref.c_str()) );
					  }
				  }
				  break;
			  case eFAST_TYPE_DECMIAL:
				  {
					  dpos = ii->m_init.find(".");
					  if ( dpos == std::string::npos)
					  {
						  exponent = atoi(ii->m_init.c_str());
					  }
					  else
					  {
						  if(ii->m_init.substr(0, dpos) != "none" ) 
						  {
							  exponent = atoi(ii->m_init.substr(0, dpos).c_str() );
						  }
						  else
						  {
							  alreadySet +=1;
						  }
						  if(ii->m_init.substr(dpos+1,ii->m_init.length()) != "none" ) 
						  {
							  mantissa = atoll(ii->m_init.substr(dpos+1,ii->m_init.length()).c_str() );
						  }
						  else
						  {
							  alreadySet +=2;
						  }
					  }
					  FastField ff(exponent, mantissa);
					  iFast.set( ii->m_tag, ff );
					  oFast.set( ii->m_tag, ff );
				  }
				  break;
			  case eFAST_TYPE_I64:
				  {
					  FastField ff((i64)atoi(ii->m_init.c_str()));
					  iFast.set( ii->m_tag, ff);
					  oFast.set( ii->m_tag, ff);
				  }
				  break;
			  case eFAST_TYPE_U64:
				  {
					  FastField ff((u64)atoi(ii->m_init.c_str()));
					  iFast.set( ii->m_tag, ff);
					  oFast.set( ii->m_tag, ff);
				  }
				  break;
			  default:
				  break;
			  }
			  if ( ii->m_init == "none" || alreadySet > 0)
			  {
				  if ( alreadySet == 0)
				  {
					  iFast.set_invalid(ii->m_tag);
					  oFast.set_invalid(ii->m_tag);
					  iFast.set_none(ii->m_tag);
					  oFast.set_none(ii->m_tag);
				  }
				  else
				  {
					  iFast.set_none(ii->m_tag, alreadySet);
					  oFast.set_none(ii->m_tag, alreadySet);
				  }
			  }
		  }
	  }
	  return true;
  }
}
